package com.zyj.core.handler.resultsethandler;

import com.zyj.core.config.MappedStatement;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

public class DefaultResuiltSetHandler implements ResultSetHandler {
    /**
     * 由结果集处理器根据mappedStatement中封装好的resultType来处理结果集
     *
     * @param statement
     * @param rs
     * @param mappedStatement
     * @param <T>
     * @return
     * @throws Exception
     */
    @Override
    public <T> List<T> handleResult(Statement statement, ResultSet rs, MappedStatement mappedStatement) throws Exception {
        // 存储解析好的结果集
        List<Object> results = new ArrayList<>();

        // 如果statement是预编译类型
        if (statement instanceof PreparedStatement) {
            PreparedStatement preparedStatement = (PreparedStatement) statement;
            Object result = null;

            // 从mappedStatement中取出封装好的resultType
            String resultType = mappedStatement.getResultType();
            // 根据名称反射得到类对象
            Class clazz = Class.forName(resultType);

            /**
             * 循环每一行数据
             */
            // 循环结果集中的每一行数据
            while (rs.next()) {
                // 从类对象中取出构造器
                Constructor constructor = clazz.getConstructor();
                // 利用构造器实例化一个结果对象
                result = constructor.newInstance();

                // 取出结果集ResultSet中的元数据
                ResultSetMetaData metaData = rs.getMetaData();
                // 从元数据中得到结果集中列的数量
                int columnCount = metaData.getColumnCount();

                /**
                 * 循环每一列数据
                 */
                // 循环每一列
                for (int i = 0; i < columnCount; i++) {
                    // 从结果集的元数据中按顺序取出列名
                    String columnName = metaData.getColumnName(i + 1);
                    // 给对象赋属性值
                    // 查询结果中的列名和要映射的对象的属性名必须一致
                    // 根据列名从类对象中取出类字段
                    Field field = clazz.getDeclaredField(columnName);
                    field.setAccessible(true);
                    // 从结果集中取出列数据，并给与列名相同的result对象字段赋值
                    field.set(result, rs.getObject(i + 1));
                }

                // 结果集添加当前结果对象
                results.add(result);
            }
        }
        return (List<T>) results;
    }
}
